﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Net;
using System.Globalization;
using System.Threading;

namespace StockTradTest.Data
{
    //获取股票历史信息
    public class GetStockHistory
    {
        public static List<Stock> stocks; public static List<Rehibilation> rehibilations;
        public static string GetHistoryFromWeb(string stockCode, DateTime start, DateTime end, string type = "cn")
        {
            //https://q.stock.sohu.com/hisHq?code=cn_601166&start=20000101&end=20200624
            string url = string.Format(@"http://q.stock.sohu.com/hisHq?code={3}_{0}&start={1}&end={2}", stockCode, start.ToString("yyyyMMdd"),
                end.ToString("yyyyMMdd"), type);
            WebClient client = new WebClient();
            try
            {
                string value = client.DownloadString(url);
                return value;
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
                return null;
            }

}
        public static void PraseHistoryData(string value)
        {
            try
            {
                stocks = new List<Stock>();
                value = value.Substring(21, value.Length - 46).Replace("\"", string.Empty);
                string[] stringSeparators = new string[] { "],[" };
                string[] stockArray = value.Split(stringSeparators, StringSplitOptions.None);
                foreach (var item in stockArray)
                {
                    //["2020-05-08","16.26","16.37","0.21","1.30%","16.21","16.52","499030","81672.91","0.25%"]
                    string[] dayStock = item.Split(',');
                    Stock stock = new Stock {
                    Date = int.Parse(dayStock[0].Replace("-","")),
                    OpenPrice = double.Parse(dayStock[1]),
                    ClosePrice = double.Parse(dayStock[2]),
                    ChangePrice = double.Parse(dayStock[3]),
                    ChangeRatio = double.Parse(dayStock[4].Substring(0, dayStock[4].Length - 2)),
                    LowPrice = double.Parse(dayStock[5]),
                    HighPrice = double.Parse(dayStock[6]),
                    TotalHand = int.Parse(dayStock[7]),
                    TotalAmount = double.Parse(dayStock[8]),
                    HandRate = dayStock[9] == "-" ? 0:double.Parse(dayStock[9].Substring(0, dayStock[9].Length - 2))};
                    stocks.Add(stock);
                }
                //升序
                stocks.Sort();
            }
            catch (WebException e)
            {
                //How do I capture this from the UI to show the error in a message box? 
                Console.WriteLine(e);
            }

        }


        public static string GetRehabilitationDataFromSina(string stockCode)
        {
            string url = string.Format(@"http://finance.sina.com.cn/realstock/company/{0}{1}/qianfuquan.js", stockCode.StartsWith("6") ? "sh" : "sz", stockCode);
            WebClient client = new WebClient();

            try
            {
                var value = client.DownloadString(url);
                value = Regex.Replace(value, "/\\*[\\s\\S]*$", "");
                return value;
            }
            catch (WebException e)
            {
                //How do I capture this from the UI to show the error in a message box? 
                Console.WriteLine(e);
                return null;
            }

        }
        //新浪数据中有部分数据顺序错误，需调整
        public static void ParseRehabiliationData(string text)
        {
            rehibilations = new List<Rehibilation>();
            string[] stringSeparators = new string[] { "data:{" };
            string[] strArray = text.Split(stringSeparators, StringSplitOptions.None)[1].Replace("}}]", "").Split(',');
            if (strArray.Length > 1)
            {

                foreach (var item in strArray)
                {
                    #region 单条记录解析
                    string[] data = item.Split(':');
                    string[] dateArray = data[0].Split('_');
                    Rehibilation sd = new Rehibilation()
                    {
                        Date = int.Parse(dateArray[1]) * 10000 + int.Parse(dateArray[2]) * 100 + int.Parse(dateArray[3]),
                        RehabilitationRate = double.Parse(data[1].Replace("\"", "")),
                    };
                    #endregion
                    rehibilations.Add(sd);
                }
                //升序
                rehibilations.Sort();
            }
        }

        /// <summary>
        /// 计算股票前复权数据
        /// </summary>
        public static bool CalcRehabilitationDayData()
        {
            try
            {
                //倒数
                bool right = rehibilations[0].Date <= stocks[0].Date;
                if (!right)
                {
                    //Console.WriteLine("Error");
                    return false;
                }
                double baseData = 1;
                //Console.WriteLine(baseData);
                //baseData / baseRate * dayRate = dayPrice;
                //倒数第一天开始，就是最大的一天
                int j = rehibilations.Count - 1;
                bool first = true;
                for (int i = stocks.Count - 1; i >= 0; i--)
                {
                    while (rehibilations[j].Date > stocks[i].Date)
                    {
                        j--;//--后日期减小

                        if (j < 0)
                        {
                            stocks.RemoveRange(0, i);
                            return true;
                        }
                    }
                    if (rehibilations[j].Date < stocks[i].Date)
                    {
                        stocks.RemoveAt(i);
                        continue;
                    }
                    if(first)
                    {
                        baseData = stocks[i].ClosePrice / rehibilations[j].RehabilitationRate;
                        first = false;
                    }
                    double rate = rehibilations[j].RehabilitationRate;

                    double closePrice = baseData * rate;
                    double baseData2 = closePrice / stocks[i].ClosePrice;
                    stocks[i].ClosePrice = Math.Round(closePrice, 2);
                    stocks[i].OpenPrice = Math.Round(stocks[i].OpenPrice * baseData2, 2);
                    stocks[i].ChangePrice = Math.Round(stocks[i].ChangePrice * baseData2, 2);
                    stocks[i].LowPrice = Math.Round(stocks[i].LowPrice * baseData2, 2);
                    stocks[i].HighPrice = Math.Round(stocks[i].HighPrice * baseData2, 2);
                    stocks[i].TotalAmount = Math.Round(stocks[i].TotalAmount * baseData2, 2);
                    j--;
                }
                return true;
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
            }

            return true;
        }

        //每日实时更新
        public static async IAsyncEnumerable<string> UpdateDayAsync(string code)
        {
            Base.CurrentCode = code;
            DateTime lastDate = DateTime.Now.AddDays(-1).Date;

            while (await Funciton.IsHolidayByDate(lastDate))
            {
                yield return lastDate.ToShortDateString() + "非交易日\r\n";
                lastDate = lastDate.AddDays(-1);
                yield return "上一日为" + lastDate.ToShortDateString() + "\r\n";
            }
            Stock lastDay = await Base.StockDatabase.GetStockAsync(int.Parse(lastDate.ToString("yyyyMMdd")));
            if (lastDay != null)
            {
                yield return code + "历史信息加载成功，最新日期" + lastDay.Date.ToString() + "\r\n";
                yield break;
            }
            yield return "历史信息获取中\r\n";
            string value = GetHistoryFromWeb(code, new DateTime(2000, 1, 1), DateTime.Now);
            if (value == null)
            {
                Thread.Sleep(500);
                value = GetHistoryFromWeb(code, new DateTime(2000, 1, 1), DateTime.Now);
                if (value == null) yield break;
            }
            if (value.Contains("existent")) yield break;
            yield return ("历史信息获取完毕\r\n");
            PraseHistoryData(value);
            yield return ("历史信息导入成功，复权信息获取中\r\n");
            string temp = GetRehabilitationDataFromSina(code);
            if (temp == null)
            {
                Thread.Sleep(500);
                temp = GetRehabilitationDataFromSina(code);
                if (value == null) yield break;
            }
            yield return ("复权信息获取完毕\r\n");
            ParseRehabiliationData(temp);
            yield return ("复权信息导入成功\r\n");
            if (CalcRehabilitationDayData())
            {
                if (stocks == null || stocks.Count == 0)
                {
                    yield return ("数据有误，存储失败\r\n");
                    yield break;
                }

                await Base.StockDatabase.SaveAllStockAsync(stocks);
                yield return ("股票数据保存成功\r\n");
                CalcIndicator.CalcAllMaForCode(stocks, out List<Indicator> indicators);
                await Base.IndicatorDatabase.SaveAllIndicatorAsync(indicators);
                yield return ("指标数据保存成功\r\n");
                yield return (code + "信息存储成功，最新时间" + DateTime.Now.ToShortDateString().ToString() + "\r\n");
            }
            else
            {
                yield return ("数据有误，存储失败\r\n");
            }

        }



    }


}
